package roteador;

import java.util.HashMap;
import java.util.Map;

public class BellmanFord {

    private ListaDeRoteamento lista;
    private Map<Integer, ListaDeRoteamento> vizinhos;
    private int roteadorId;

    public BellmanFord(int roteadorID) {
        this.roteadorId = roteadorID;
        lista = new ListaDeRoteamento(roteadorID);
        vizinhos = new HashMap<Integer, ListaDeRoteamento>();
    }

    public void addVizinho(DistanciaRoteador dr) {

        vizinhos.put(dr.getDestino(), new ListaDeRoteamento(dr.getDestino()));
        System.out.println("adicionou vizinho " + dr.getDestino());
        DistanciaRoteador dro = lista.get(dr.getDestino());
        if (dro == null) {
            lista.addCustoDistancia(new DistanciaRoteador(dr.getDestino(), dr.getCusto(), dr.getDestino()));

        } else {
            if (dro.getCusto() > dr.getCusto()) {
                lista.addCustoDistancia(new DistanciaRoteador(dr.getDestino(),
                        dr.getCusto(), dr.getDestino()));
            }
        }

    }

    public boolean removerVizinho(int idVizinho) {

        vizinhos.remove(idVizinho);
        boolean mudou = false;
        if (lista.contains(idVizinho)) {
            lista.remove(idVizinho);
            mudou = true;
        }
        refazFim:
        while (true) {
            for (DistanciaRoteador dv : lista) {
                if (dv.getPrimeiroVizinho() == idVizinho) {
                    lista.remove(dv.getDestino());
                    DistanciaRoteador menorDistancia = encontrarMenorCaminho(dv.getDestino());
                    if (menorDistancia != null) {
                        lista.addCustoDistancia(menorDistancia);
                    }

                    mudou = true;
                    continue refazFim;
                }

            }
            break;
        }

        return mudou;

    }

    private DistanciaRoteador encontrarMenorCaminho(int destino) {
        DistanciaRoteador dr = null;

        for (ListaDeRoteamento lista : vizinhos.values()) {
            DistanciaRoteador roteador = lista.get(destino);
            if (roteador != null) {
                int custo = lista.getCustoVizinho(lista.getIdRoteador());
                if (custo == -1) {
                    continue;
                }
                DistanciaRoteador drAux = new DistanciaRoteador(destino, custo
                        + roteador.getCusto(), lista.getIdRoteador());
                if (dr == null || drAux.getCusto() < dr.getCusto()) {
                    dr = drAux;
                }
            }
        }

        if (lista.get(destino) != null) {
            if (dr == null || lista.getCustoVizinho(destino) < dr.getCusto()) {
                return lista.get(destino);
            }
        }

        return dr;

    }

    public byte[] getVetorDistancia() {
        String messagem = roteadorId + "";
        for (DistanciaRoteador dr : lista) {
            messagem += dr.gerarMessagem();
        }
        return messagem.getBytes();
    }

    public boolean atualizaListaDoVizinho(ListaDeRoteamento listaVetorDistancia) {
        boolean mudou = false;
        for (DistanciaRoteador distanciaRoteador : lista) {
            if (distanciaRoteador.getPrimeiroVizinho() == listaVetorDistancia.getIdRoteador()) {
                if (listaVetorDistancia.get(distanciaRoteador.getDestino()) == null) {
                    lista.remove(distanciaRoteador.getDestino());
                    DistanciaRoteador menorDistancia = encontrarMenorCaminho(distanciaRoteador.getDestino());
                    if (menorDistancia != null) {
                        lista.addCustoDistancia(menorDistancia);
                    }

                    mudou = true;
                }

            }
        }
        return mudou;
    }

    public boolean atualizarTabelaVizinho(ListaDeRoteamento listaVetorDistancia) {
        boolean mudou = false;
        int idRoteadorVizinho = listaVetorDistancia.getIdRoteador();
        if (vizinhos.containsKey(idRoteadorVizinho)) {
            vizinhos.put(idRoteadorVizinho, listaVetorDistancia);
            mudou = atualizaListaDoVizinho(listaVetorDistancia);

        }
        for (DistanciaRoteador lr : listaVetorDistancia) {

            DistanciaRoteador minhaDistanciaRoteador = lista.get(lr.getDestino());

            int custoVizinho = lista.getCustoVizinho(idRoteadorVizinho);

            if (minhaDistanciaRoteador == null
                    || minhaDistanciaRoteador.getCusto() > lr.getCusto()
                    + custoVizinho) {
                mudou = true;
                if (custoVizinho > 0) {
                    lista.addCustoDistancia(new DistanciaRoteador(lr.getDestino(), custoVizinho + lr.getCusto(),
                            idRoteadorVizinho));
                }

            }
        }
        if (mudou) {
            System.out.println("tabela de roteamento do roteador " + roteadorId
                    + " mudou.");
        }
        return mudou;

    }

    public void atualizarListaRoteamento(DistanciaRoteador dr) {

        lista.addCustoDistancia(dr);

    }
}
